import _ from 'lodash'
import {article, section} from './lablog.js'

const {concat} = _
article("We've seen how to write programs which pipe data through a series of pure functions.")
article("But what about control flow, error handling, asynchronous actions, state, effect?")
section("Functor 是实现了 map 函数并遵守一些特定规则的容器类型")
const Container = function(x) {
    this.__value = x
}
Container.of = x => new Container(x)

console.log("Container.of(3)=", Container.of(3))

console.log("Container.of('hello')=", Container.of('hello'))

Container.prototype.map = function(f) {
    return Container.of(f(this.__value))
}

console.log(Container.of(2).map(x => x + 2))
console.log(Container.of("hello .").map(x => x.toUpperCase()))
console.log(Container.of("ok").map(x => concat(x, '-hello')).map(x => x.join("").length))

const Maybe = function(x) {
    this.__value = x
}
Maybe.of = function(x) {
    return new Maybe(x)
}
Maybe.prototype.isNothing = function() {
    return (this.__value === null || this.__value === undefined)
}
Maybe.prototype.map = function(f) {
    return this.isNothing() ? Maybe.of(null) : Maybe.of(f(this.__value))
}

section("引入 Maybe 来与 null 打交道。我们想要的值深藏在 Maybe 对象中，且只能通过 map 操作它。本质上，这是一种强制执行的空值检查。类似这样的 API 能够将应用升级为健壮的应用。")
const add = _.curry((x, y) => x + y)
const match = _.curryRight((str, reg) => str.match(reg))
console.log(Maybe.of("markdown").map(match(/a/ig)))
console.log(Maybe.of(null).map(match(/a/ig)))
console.log(Maybe.of({name: 'hhg'}).map(_.property("age")).map(add(10)))
console.log(Maybe.of({name: 'hhg', age: 15}).map(_.property("age")).map(add(10)))

section("有时候函数可以明确返回 null 来表示失败")
const withdraw = _.curry((amount, account) => {
    return account.balance >= amount ?
        Maybe.of({balance: account.balance - amount}) :
        Maybe.of(null)
})
const withdrawTwenty = withdraw(20)
console.log("从 200 账户取款 20:", withdrawTwenty({balance: 200}))
console.log("从 10 账户取款 20:", withdrawTwenty({balance: 10}))


section("释放容器中的值")
section("任何事物都有个最终尽头，那些会产生作用的函数，最终都要有一个结束。不过无法通过 return 将输出传递到外界，必须要运行这样那样的函数才可以。")
section("应用程序所做的工作就是读取、更改和保存数据直到不再需要它们。")
const maybe = _.curry((x, f, m) => {
    return m.isNothing() ? x : f(m.__value)
})
const fininshTrans = (x) => {
    return "You finished transaction, balance:\t" + JSON.stringify(x)
}
const getTwenty = _.flowRight(
    maybe("You're broke!", fininshTrans),
    withdrawTwenty
)
console.log("从 200 账户取款 20:", getTwenty({balance: 200}))
console.log("从 10 账户取款 20:", getTwenty({balance: 10}))